#ifndef THIRDNLI386_H_INCLUDED
#define THIRDNLI386_H_INCLUDED

struct GDTEntry
{
    u16 limit;
    u16 base;
    u8 base_23_16;
    u8 type;
    u8 flags;
    u8 base_31_24;
} __attribute__((packed));

struct IDTEntry
{
    u16 offset_15_0;
    u16 selector;
    u8 undef;
    u8 type;
    u16 offset_31_16;
} __attribute__((packed));

struct LDTEntry
{
    u16 limit;
    u16 base;
    u8 base_23_16;
    u8 type;
    u8 flags;
    u8 base_31_24;
} __attribute__((packed));

struct	GDTPtr
{
    u16 size;
    u32 addrs;
} __attribute__((packed));

struct	IDTPtr
{
    u16 size;
    u32 addrs;
} __attribute__((packed));

struct	LDTPtr
{
    u16 size;
    LDTEntry *addrs;
} __attribute__((packed));



static GDTPtr PointGDT;
static IDTPtr PointIDT;
//static LDTPtr PointLDT;

struct Tss_32
{
    u16 prev_task_link;
    u16 Reserv01;
    u32 esp0;
    u16 ss0;
    u16 Reserv02;
    u32 esp1;
    u16 ss1;
    u16 Reserv03;
    u32 esp2;
    u16 ss2;
    u16 Reserv04;
    u32 cr3;
    u32 eip;
    u32 eflags;
    u32 eax;
    u32 ecx;
    u32 edx;
    u32 ebx;
    u32 esp;
    u32 ebp;
    u32 esi;
    u32 edi;
    u16 es;
    u16 Reserv05;
    u16 cs; // used as test too
    u16 Reserv06;
    u16 ss;
    u16 Reserv07;
    u16 ds;
    u16 Reserv08;
    u16 fs;
    u16 Reserv09;
    u16 gs;
    u16 Reserv10;
    u16 ldt_selector;
    u16 Reserv11;
    u32  t;
    u32 io_map;
} __attribute__((packed));

struct	Task
{
    u16 Selector;
    u16 TssTable;
    LDTEntry *addrs;
};

static void(*IRQsAdrs[20])();

class MMU
{
#define prsnt_rng0_data_r0_naccssd 0x90	//present, ring 0, data, read only, not accessed. generate this binary 	10010000
#define prsnt_rng0_data_rw_naccssd 0x92	//;present, ring 0, data, read/wright, not accessed. generate this binary 	10010010
#define prsnt_rng0_stck_r0_naccssd 0x94	//;present, ring 0, stack, read only, not accessed. generate this binary 	10010100
#define prsnt_rng0_stck_rw_naccssd 0x96	//;present, ring 0, stack, read/wright, not accessed. generate this binary 10010110
#define prsnt_rng0_code_e0_naccssd 0x98	//;present, ring 0, code, exec only, not accessed. generate this binary 	10011000
#define prsnt_rng0_code_er_naccssd 0x9a	//;present, ring 0, code, exec read, not accessed. generate this binary 	10011010
#define prsnt_rng0_code_e0_naccssd_c 0x9c	//;present, ring 0, code, exec only, not accessed, conforming.  			10011100
#define prsnt_rng0_code_er_naccssd_c 0x9e	//;present, ring 0, code, exec read, not accessed, conforming.  			10011110
#define intrrgt_rng0 0x8e
#define tss_p_rng0 0x89			  //;tss ring 0//////////
#define tskgt_rng0 0x85				//;task gate ring 0
#define tss_p_rng0b 0x8b
#define DefaultEflag    0x4202      //ints enabled, nasted task,

    static GDTEntry GDT[8192];
    static IDTEntry IDT[255];
    static LDTEntry LDT[8192];
    static Tss_32 TSSs[200];

    static Task Tasks[200];

    static const u8 GDTInitDesc[5];

    static int GDTCounter;
    static int IDTCounter;
    static int LDTCounter;
    static int TSSCounter;

    static u16 GetGDT();
    static u16 GetIDT();
    static u16 GetLDT();
    static u16 GetTSS();

    static inline void LGDT(GDTPtr *gdt);
    static inline void LIDT(IDTPtr *idt);
    static inline void LLDT(LDTPtr *ldt);
    static inline void LTR(u16 Sel);
    static inline u16 STR();

    static void Divideerror();
    static void Debugexceptions();
    static void Nonmaskableinterrupt();
    static void Breakpoint();
    static void Overflow();
    static void Boundscheck();
    static void Invalidopcode();
    static void Coprocessornotavailable();
    static void Doublefault();
    static void reserved0();
    static void InvalidTSS();
    static void Segmentnotpresent();
    static void Stackexception();
    static void Generalprotection(u32 error);
    static void Pagefault();
    static void reserved1();
    static void Coprecessorerror();
    static void reserved2();

    static const u32 IDTInitDesc[32];

    static u16 MakeSelector(int selnumb, int table, int ring);

    static inline void ISREnter();
    static inline void ISRExit();

    static void inline addGDTDesc(u32 limit, u32 base, u8 type, u8 flags);
    static void inline addIDTDesc(u32 base, u16 sel, u8 type);

    static void inline ToSchedIRQHandler(u8 numb);

    static void inline Scheduler();

    static void IRQ01();
    static void IRQ02();
    static void IRQ03();
    static void IRQ04();
    static void IRQ05();
    static void IRQ06();
    static void IRQ07();
    static void IRQ08();
    static void IRQ09();
    static void IRQ10();
    static void IRQ11();
    static void IRQ12();
    static void IRQ13();
    static void IRQ14();
    static void IRQ15();
    static void IRQ16();

    static bool ServingIRQ01;
    static bool ServingIRQ02;
    static bool ServingIRQ03;
    static bool ServingIRQ04;
    static bool ServingIRQ05;
    static bool ServingIRQ06;
    static bool ServingIRQ07;
    static bool ServingIRQ08;
    static bool ServingIRQ09;
    static bool ServingIRQ10;
    static bool ServingIRQ11;
    static bool ServingIRQ12;
    static bool ServingIRQ13;
    static bool ServingIRQ14;
    static bool ServingIRQ15;
    static bool ServingIRQ16;

    static void HandlerIRQ01();
    static void HandlerIRQ02();
    static void HandlerIRQ03();
    static void HandlerIRQ04();
    static void HandlerIRQ05();
    static void HandlerIRQ06();
    static void HandlerIRQ07();
    static void HandlerIRQ08();
    static void HandlerIRQ09();
    static void HandlerIRQ10();
    static void HandlerIRQ11();
    static void HandlerIRQ12();
    static void HandlerIRQ13();
    static void HandlerIRQ14();
    static void HandlerIRQ15();
    static void HandlerIRQ16();

    static u8 InstalledIRQs;

    static const u32 IRQsLocalAdrs[16];

    static const u32 IRQsLocalAdrsHandlers[16];

    static void inline cli()
    {
        asm("cli");
    }
    static void inline sti()
    {
        asm("sti");
    }

public:
    MMU()
    {
        //LGDT(&PointGDT);
        //LIDT(&PointIDT);
    }

    static void inline Init();
    void inline addIRQ(void(*offset)());
};

GDTEntry MMU::GDT[8192];
IDTEntry MMU::IDT[255];
LDTEntry MMU::LDT[8192];

Tss_32 MMU::TSSs[200];

Task MMU::Tasks[200];

const u8 MMU::GDTInitDesc[5] =
{
    prsnt_rng0_code_er_naccssd,
    prsnt_rng0_data_rw_naccssd,
    prsnt_rng0_data_rw_naccssd,
    prsnt_rng0_data_rw_naccssd,
    prsnt_rng0_data_rw_naccssd
};

const u32 MMU::IDTInitDesc[32] =
{
    (u32)&Divideerror,
    (u32)&Debugexceptions,
    (u32)&Nonmaskableinterrupt,
    (u32)&Breakpoint,
    (u32)&Overflow,
    (u32)&Boundscheck,
    (u32)&Invalidopcode,
    (u32)&Coprocessornotavailable,
    (u32)&Doublefault,
    (u32)&reserved0,
    (u32)&InvalidTSS,
    (u32)&Segmentnotpresent,
    (u32)&Stackexception,
    (u32)&Generalprotection,
    (u32)&Pagefault,
    (u32)&reserved1,
    (u32)&Coprecessorerror,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,
    (u32)&reserved2,

};

u16 MMU::MakeSelector(int selnumb, int table, int ring)
{
    u16 Selector = selnumb * 8;

    if(table)
    {
        Selector = (Selector + 4);
    }
    if(ring)
    {
        Selector = (Selector + 3);
    }

    return Selector;
}

int MMU::GDTCounter =1; //does not use first desc
int MMU::IDTCounter =50;
int MMU::LDTCounter =0;
int MMU::TSSCounter =0;

u16 MMU::GetGDT()
{
    return GDTCounter++;// ! Do a better checking
}
u16 MMU::GetIDT()
{
    for(u32 i = 0; i < 255; i++)
    {
        if(!IDT[i].type)
        {
            IDTCounter++;
            if(IDTCounter > 255)
            {
                IDTCounter = 255;
            }
            return i;
        }
    }
    return -1;// ! 50 is reserved
}

u16 MMU::GetLDT()
{
    return LDTCounter++; // !
}

u16 MMU::GetTSS()
{
    for(u32 i = 0; i < 200; i++)
    {
        if(!TSSs[i].cs)
        {
            TSSCounter++;
            if(TSSCounter > 200)
            {
                TSSCounter = 200;
                return -1;
            }
            return i;
        }
    }
    return - 1; // !
}

void MMU::LGDT(GDTPtr *gdt)
{
    gdt->size = GDTCounter * 8 - 1;
    gdt->addrs = (u32)&GDT;

    asm("lgdt %0" :: "m" (*gdt));
}

void MMU::LIDT(IDTPtr *idt)
{
    idt->size = IDTCounter * 8;
    idt->addrs = (u32)&IDT;

    asm("lidt %0" :: "m" (*idt));
}

void MMU::LLDT(LDTPtr *ldt)
{

}

void MMU::LTR(u16 Sel)
{
    asm volatile("ltr %0" :: "r" (Sel));
}


u16 MMU::STR()
{
    u16 sel;
asm("str %0" : "=m" (sel));

    return sel;
}

void MMU::Init()
{
    for(u32 i = 0; i < 5; i++ )
    {
        addGDTDesc(0xFFFFFFF,0,GDTInitDesc[i],0xc0);
    }

    cli();

    LGDT(&PointGDT);

    asm("pushl %eax\n"
        "movl  	%cr0, %eax\n"
        "bts    $1, %eax\n"
        "movl  	%eax,%cr0\n"
        "ljmp   $0x08,$flush  \n"
        "flush:	\n"
        "movw	$0x10,%ax\n"
        "movw	%ax,%ds\n"
        "movw	%ax,%ss\n"
        "movl	$0X20000,%esp\n"
        //"movl	%%eax,%%esp\n"
        "movw	$0x18,%ax\n"
        "movw	%ax,%es\n"
        "movw	$0x20,%ax\n"
        "movw	%ax,%gs\n"
        "movw	$0x28,%ax\n"
        "movw	%ax,%fs\n"
        "popl   %eax\n");

    for(u32 i = 0; i < 32; i++ )
    {

        u32 TSSEntry = GetTSS();
        u32 base = (u32)&TSSs[TSSEntry];
        u32 limit = 0x67;
        u8 flags = 0x80;

        TSSs[TSSEntry].ldt_selector = 0;
        TSSs[TSSEntry].esp = 0x3000;
        TSSs[TSSEntry].ss0 = MakeSelector(2,0,0);
        TSSs[TSSEntry].eflags = DefaultEflag;
        TSSs[TSSEntry].ds = MakeSelector(2,0,0);
        TSSs[TSSEntry].es = MakeSelector(3,0,0);
        TSSs[TSSEntry].fs = MakeSelector(4,0,0);
        TSSs[TSSEntry].ss = MakeSelector(2,0,0);
        TSSs[TSSEntry].gs = MakeSelector(2,0,0);
        TSSs[TSSEntry].cs = MakeSelector(1,0,0);
        TSSs[TSSEntry].eip = IDTInitDesc[i];

        addGDTDesc(limit,base,tss_p_rng0,flags);

        addIDTDesc(0,MakeSelector(GDTCounter - 1,0,0),tskgt_rng0);
    }

    LIDT(&PointIDT);

    IDT[50].type = tskgt_rng0; // reserve for task switch

    u32 base = (u32)&TSSs[GetTSS()];
    u32 limit = 0x67;
    u8 flags = 0x80;

    addGDTDesc(limit,base,tss_p_rng0,flags);

    LTR(MakeSelector(GDTCounter -1,0,0));


}

void MMU::addGDTDesc(u32 limit, u32 base, u8 type, u8 flags)
{
    u8 limitflag = 0;
    limitflag = (((limit >> 16) & 0x0F) | (flags & 0xF0));//join
    u32 Entry = GetGDT();
    GDT[Entry].base_31_24 = (base >> 24);
    GDT[Entry].base_23_16 = (base >> 16);
    GDT[Entry].base = base;
    GDT[Entry].type = type;
    GDT[Entry].limit = limit;
    GDT[Entry].flags = limitflag;

    LGDT(&PointGDT);
}

void MMU::addIDTDesc(u32 base, u16 sel, u8 type)
{
    u32 Entry = GetIDT();
    IDT[Entry].offset_15_0 = (base >> 0);
    IDT[Entry].selector = sel;
    IDT[Entry].undef = 0;
    IDT[Entry].type = type;
    IDT[Entry].offset_31_16 = (base >> 16);

    LIDT(&PointIDT);
}

void MMU::ToSchedIRQHandler(u8 numb)
{
    u32 TSSEntry = GetTSS();
    u32 base = (u32)&TSSs[TSSEntry];
    u32 limit = 0x67;
    u8 flags = 0x80;

    addGDTDesc(limit,base,tss_p_rng0,flags);

    TSSs[TSSEntry].ldt_selector = 0;
    TSSs[TSSEntry].esp = 0x30000;// !
    TSSs[TSSEntry].ss0 = MakeSelector(2,0,0);
    TSSs[TSSEntry].eflags = DefaultEflag;
    TSSs[TSSEntry].ds = MakeSelector(2,0,0);
    TSSs[TSSEntry].es = MakeSelector(3,0,0);
    TSSs[TSSEntry].fs = MakeSelector(4,0,0);
    TSSs[TSSEntry].ss = MakeSelector(2,0,0);
    TSSs[TSSEntry].gs = MakeSelector(2,0,0);
    TSSs[TSSEntry].cs = MakeSelector(1,0,0);
    TSSs[TSSEntry].eip = IRQsLocalAdrsHandlers[numb];

    Tasks[0].Selector = MakeSelector(GDTCounter - 1,0,0);
    Tasks[0].TssTable = TSSEntry;

}

void MMU::Scheduler()
{
    IDT[50].selector = Tasks[0].Selector;
    asm("int $50");
}

void MMU::IRQ01()
{
    asm("pushal");

    if(!ServingIRQ01)
    {
        ToSchedIRQHandler(0);


        // ! do check if its already servicing the irq handler
    }
    Scheduler();

    asm("popal");
    //asm("iret"); ///!
}

void MMU::IRQ02()
{

    asm("iret");
}

void MMU::IRQ03()
{

    asm("iret");
}

void MMU::IRQ04()
{

    asm("iret");
}

void MMU::IRQ05()
{

    asm("iret");
}

void MMU::IRQ06()
{

    asm("iret");
}

void MMU::IRQ07()
{

    asm("iret");
}

void MMU::IRQ08()
{

    asm("iret");
}

void MMU::IRQ09()
{

    asm("iret");
}

void MMU::IRQ10()
{

    asm("iret");
}

void MMU::IRQ11()
{

    asm("iret");
}

void MMU::IRQ12()
{

    asm("iret");
}

void MMU::IRQ13()
{

    asm("iret");
}

void MMU::IRQ14()
{

    asm("iret");
}

void MMU::IRQ15()
{

    asm("iret");
}

void MMU::IRQ16()
{
    asm("iret");
}

bool MMU::ServingIRQ01 = false;
bool MMU::ServingIRQ02 = false;
bool MMU::ServingIRQ03 = false;
bool MMU::ServingIRQ04 = false;
bool MMU::ServingIRQ05 = false;
bool MMU::ServingIRQ06 = false;
bool MMU::ServingIRQ07 = false;
bool MMU::ServingIRQ08 = false;
bool MMU::ServingIRQ09 = false;
bool MMU::ServingIRQ10 = false;
bool MMU::ServingIRQ11 = false;
bool MMU::ServingIRQ12 = false;
bool MMU::ServingIRQ13 = false;
bool MMU::ServingIRQ14 = false;
bool MMU::ServingIRQ15 = false;
bool MMU::ServingIRQ16 = false;

void MMU::HandlerIRQ01()
{
    // ! do checking wheter the handler has returned
    (IRQsAdrs[0])(); // call IRQ ISR
    GDT[STR() / 8].type = 0; // free tss
    TSSs[Tasks[0].TssTable].cs = 0;
    Tasks[0].TssTable = 0;
    ServingIRQ01 = false;
    asm("iret");
}
void MMU::HandlerIRQ02()
{

}
void MMU::HandlerIRQ03()
{

}
void MMU::HandlerIRQ04()
{

}
void MMU::HandlerIRQ05()
{

}
void MMU::HandlerIRQ06()
{

}
void MMU::HandlerIRQ07()
{

}
void MMU::HandlerIRQ08()
{

}
void MMU::HandlerIRQ09()
{

}
void MMU::HandlerIRQ10()
{

}
void MMU::HandlerIRQ11()
{

}
void MMU::HandlerIRQ12()
{

}
void MMU::HandlerIRQ13()
{

}
void MMU::HandlerIRQ14()
{

}
void MMU::HandlerIRQ15()
{

}
void MMU::HandlerIRQ16()
{

}
u8 MMU::InstalledIRQs = 0;

const u32 MMU::IRQsLocalAdrs[16] =
{
    (u32)&IRQ01,
    (u32)&IRQ02,
    (u32)&IRQ03,
    (u32)&IRQ04,
    (u32)&IRQ05,
    (u32)&IRQ06,
    (u32)&IRQ07,
    (u32)&IRQ08,
    (u32)&IRQ09,
    (u32)&IRQ10,
    (u32)&IRQ11,
    (u32)&IRQ12,
    (u32)&IRQ13,
    (u32)&IRQ14,
    (u32)&IRQ15,
    (u32)&IRQ16,
};

const u32 MMU::IRQsLocalAdrsHandlers[16] =
{
    (u32)&HandlerIRQ01,
    (u32)&HandlerIRQ02,
    (u32)&HandlerIRQ03,
    (u32)&HandlerIRQ04,
    (u32)&HandlerIRQ05,
    (u32)&HandlerIRQ06,
    (u32)&HandlerIRQ07,
    (u32)&HandlerIRQ08,
    (u32)&HandlerIRQ09,
    (u32)&HandlerIRQ10,
    (u32)&HandlerIRQ11,
    (u32)&HandlerIRQ12,
    (u32)&HandlerIRQ13,
    (u32)&HandlerIRQ14,
    (u32)&HandlerIRQ15,
    (u32)&HandlerIRQ16,
};

void MMU::addIRQ(void(*offset)())
{
    if(InstalledIRQs > 16)
    {
        return;
    }

    IRQsAdrs[InstalledIRQs] = offset;

    addIDTDesc(IRQsLocalAdrs[InstalledIRQs],MakeSelector(1,0,0),intrrgt_rng0);

    InstalledIRQs++; // leave set for new
}

void MMU::ISREnter()
{

    //(IRQsAdrs[0])();

    asm("iret");
}

void MMU::ISRExit()
{


    asm("iret");
}

void MMU::Divideerror()
{
    const u8 msg[] = {"Devide error"};

    u8* videoPtr = (u8*)0xB8200;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Debugexceptions()
{
    const u8 msg[] = {"Debugexceptions"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Nonmaskableinterrupt()
{

    const u8 msg[] = {"Nonmaskableinterrupt"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Breakpoint()
{


    const u8 msg[] = {"Breakpoint"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::Overflow()
{

    const u8 msg[] = {"Overflow"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Boundscheck()
{

    const u8 msg[] = {"Boundscheck"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Invalidopcode()
{


    const u8 msg[] = {"Invalidopcode"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::Coprocessornotavailable()
{


    const u8 msg[] = {"Coprocessornotavailable"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::Doublefault()
{


    const u8 msg[] = {"Doublefault"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::reserved0()
{


    const u8 msg[] = {"reserved0"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::InvalidTSS()
{

    const u8 msg[] = {"InvalidTSS"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Segmentnotpresent()
{

    const u8 msg[] = {"Segmentnotpresent"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Stackexception()
{

    const u8 msg[] = {"Stackexception"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Generalprotection(u32 error)
{

    const u8 msg[] = {"Generalprotection"};

    u8* videoPtr = (u8*)0xB8300;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Pagefault()
{


    const u8 msg[] = {"Pagefault"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();

}
void MMU::reserved1()
{

    const u8 msg[] = {"reserved1"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}
void MMU::Coprecessorerror()
{


    const u8 msg[] = {"Coprecessorerror"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }
    ISRExit();
}
void MMU::reserved2()
{


    const u8 msg[] = {"reserved2"};

    u8* videoPtr = (u8*)0xB8000;

    for(u32 i = 0; i < sizeof msg; i++)
    {

        *videoPtr++ = msg[i];
        *videoPtr++ = 15;
    }

    ISRExit();
}

#endif // THIRDNLI386_H_INCLUDED
